using System.Collections.Generic;
using UnityEngine;
using VoxelEngine.Utils;

namespace VoxelEngine
{
	internal static class ChunkRenderer
	{
		private static class Direction
		{
			public const int Up = 0;

			public const int Down = 1;

			public const int Left = 2;

			public const int Right = 3;
		}

		private enum FaceDirection
		{
			Top,
			Bottom,
			Front,
			Back,
			Left,
			Right
		}

		private enum RenderColliderType
		{
			SolidBlockAndCollider,
			WaterNoCollider,
			CutoutNoCollider,
			ColliderOnly
		}

		private static bool _lightAttenuation;

		private static bool _smoothLight;

		private static bool _voxelBorder;

		private static bool _isVoxelColoring;

		private static bool _isVoxelColoringEditor;

		private static float[,] _worldHeight;

		private static readonly List<Block> _lightBlocks = new List<Block>();

		private static List<Vector3> _vertices = new List<Vector3>();

		private static List<Color32> _colors = new List<Color32>();

		private static readonly List<int>[] _triangles = new List<int>[5]
		{
			new List<int>(),
			new List<int>(),
			new List<int>(),
			new List<int>(),
			new List<int>()
		};

		private static List<Vector2> _uvs = new List<Vector2>();

		private static List<Vector2> _uvs2 = new List<Vector2>();

		private static Vector3 _pos = default(Vector3);

		private static bool[] _border = new bool[4];

		private static readonly Vector3 _vector010 = new Vector3(0f, 1f, 0f);

		private static readonly Vector3 _vector011 = new Vector3(0f, 1f, 1f);

		private static readonly Vector3 _vector110 = new Vector3(1f, 1f, 0f);

		private static readonly Vector3 _vector100 = new Vector3(1f, 0f, 0f);

		private static readonly Vector3 _vector101 = new Vector3(1f, 0f, 1f);

		private static readonly Vector3 _vector001 = new Vector3(0f, 0f, 1f);

		private static readonly Vector3 _vector050 = new Vector3(0f, 0.5f, 0f);

		private static readonly Vector3 _vector051 = new Vector3(0f, 0.5f, 1f);

		private static readonly Vector3 _vector150 = new Vector3(1f, 0.5f, 0f);

		private static readonly Vector3 _vector151 = new Vector3(1f, 0.5f, 1f);

		private static readonly Vector3 _vectorDiag1_1 = new Vector3(0.95968f, 0.95968f, 1.15f);

		private static readonly Vector3 _vectorDiag1_2 = new Vector3(0.95968f, 0.95968f, -0.15f);

		private static readonly Vector3 _vectorDiag1_3 = new Vector3(0.04032f, 0.04032f, -0.15f);

		private static readonly Vector3 _vectorDiag1_4 = new Vector3(0.04032f, 0.04032f, 1.15f);

		private static readonly Vector3 _vectorDiag2_1 = new Vector3(0.04032f, -0.15f, 0.04032f);

		private static readonly Vector3 _vectorDiag2_2 = new Vector3(0.04032f, 1.15f, 0.04032f);

		private static readonly Vector3 _vectorDiag2_3 = new Vector3(0.95968f, 1.15f, 0.95968f);

		private static readonly Vector3 _vectorDiag2_4 = new Vector3(0.95968f, -0.15f, 0.95968f);

		private static readonly Vector3 _vectorDiag3_1 = new Vector3(0.04032f, 0.95968f, 1.15f);

		private static readonly Vector3 _vectorDiag3_2 = new Vector3(0.95968f, 0.04032f, 1.15f);

		private static readonly Vector3 _vectorDiag3_3 = new Vector3(0.95968f, 0.04032f, -0.15f);

		private static readonly Vector3 _vectorDiag3_4 = new Vector3(0.04032f, 0.95968f, -0.15f);

		private static readonly Vector3 _vectorDiag4_1 = new Vector3(-0.15f, 0.04032f, 0.95968f);

		private static readonly Vector3 _vectorDiag4_2 = new Vector3(-0.15f, 0.95968f, 0.04032f);

		private static readonly Vector3 _vectorDiag4_3 = new Vector3(1.15f, 0.95968f, 0.04032f);

		private static readonly Vector3 _vectorDiag4_4 = new Vector3(1.15f, 0.04032f, 0.95968f);

		private static readonly Vector3 _vectorDiag5_1 = new Vector3(0.95968f, -0.15f, 0.04032f);

		private static readonly Vector3 _vectorDiag5_2 = new Vector3(0.04032f, -0.15f, 0.95968f);

		private static readonly Vector3 _vectorDiag5_3 = new Vector3(0.04032f, 1.15f, 0.95968f);

		private static readonly Vector3 _vectorDiag5_4 = new Vector3(0.95968f, 1.15f, 0.04032f);

		private static readonly Vector3 _vectorDiag6_1 = new Vector3(-0.15f, 0.95968f, 0.95968f);

		private static readonly Vector3 _vectorDiag6_2 = new Vector3(1.15f, 0.95968f, 0.95968f);

		private static readonly Vector3 _vectorDiag6_3 = new Vector3(1.15f, 0.04032f, 0.04032f);

		private static readonly Vector3 _vectorDiag6_4 = new Vector3(-0.15f, 0.04032f, 0.04032f);

		private static readonly Vector3 _vector111 = Vector3.one;

		private static readonly Vector3 _vector000 = Vector3.zero;

		private static readonly Vector2 _collisionUV = new Vector2(0.875f, 0f);

		private const int _lightSpread = 5;

		private static byte[] _lightNeighbours = new byte[6];

		public static bool LightAttenuation
		{
			set
			{
				_lightAttenuation = value;
			}
		}

		public static bool SmoothLight
		{
			set
			{
				_smoothLight = value;
			}
		}

		public static bool VoxelBorder
		{
			set
			{
				_voxelBorder = value;
			}
		}

		public static bool IsVoxelColoring
		{
			set
			{
				_isVoxelColoring = value;
			}
		}

		public static bool IsVoxelColoringEditor
		{
			get
			{
				return _isVoxelColoringEditor;
			}
			set
			{
				_isVoxelColoringEditor = value;
			}
		}

		public static float[,] WorldHeight
		{
			get
			{
				return _worldHeight;
			}
			set
			{
				_worldHeight = value;
			}
		}

		public static void Free()
		{
			CleanMesh();
			_lightBlocks.Clear();
		}

		private static void CleanMesh()
		{
			_vertices.Clear();
			_colors.Clear();
			for (int i = 0; i < _triangles.Length; i++)
			{
				_triangles[i].Clear();
			}
			_uvs.Clear();
			_uvs2.Clear();
		}

		public static void Render(Chunk chunk, ChunkObject chunkObject)
		{
			Mesh mesh = chunkObject.ChunkMesh.sharedMesh;
			if (mesh == null)
			{
				mesh = new Mesh();
				mesh.MarkDynamic();
			}
			Mesh mesh2 = chunkObject.ChunkCollider.sharedMesh;
			if (mesh2 == null)
			{
				mesh2 = new Mesh();
				mesh2.MarkDynamic();
			}
			CleanMesh();
			for (int i = 0; i < 8; i++)
			{
				for (int j = 0; j < 8; j++)
				{
					for (int k = 0; k < 8; k++)
					{
						Block block = chunk[i, j, k];
						block.Spawn3DModelIfNeeded();
						if (!block.IsSolid() && block.Type != BlockType.Water)
						{
							continue;
						}
						Block block2 = chunk[i, j + 1, k];
						Block block3 = chunk[i, j, k + 1];
						Block block4 = chunk[i + 1, j, k];
						Block block5 = chunk[i, j, k - 1];
						Block block6 = chunk[i - 1, j, k];
						Block block7 = chunk[i, j - 1, k];
						BlockVolume currentBlockVolume = block.Volume();
						bool currentBlockIsCutout = block.IsCutout();
						bool collisionFace = false;
						if (block.IsCollapsedBlock())
						{
							CreateSpriteBlock(block2, block3, block4, block5, block6, block7, block, chunk, i, j, k);
							collisionFace = true;
							continue;
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block2, FaceDirection.Top))
						{
							CreateTopFace(block2, block, chunk, i, j, k, collisionFace);
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block3, FaceDirection.Front))
						{
							CreateFrontFace(block3, block, chunk, i, j, k, collisionFace);
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block4, FaceDirection.Left))
						{
							CreateLeftFace(block4, block, chunk, i, j, k, collisionFace);
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block5, FaceDirection.Back))
						{
							CreateBackFace(block5, block, chunk, i, j, k, collisionFace);
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block6, FaceDirection.Right))
						{
							CreateRightFace(block6, block, chunk, i, j, k, collisionFace);
						}
						if (IsFaceRenderable(currentBlockVolume, currentBlockIsCutout, block, block7, FaceDirection.Bottom))
						{
							CreateBottomFace(block7, block, chunk, i, j, k, collisionFace);
						}
					}
				}
			}
			mesh.SetVertices(_vertices);
			mesh.SetColors(_colors);
			mesh.subMeshCount = 3;
			mesh.SetTriangles(_triangles[0], 0);
			mesh.SetTriangles(_triangles[1], 1);
			mesh.SetTriangles(_triangles[2], 2);
			mesh.SetUVs(0, _uvs);
			mesh.SetUVs(1, _uvs2);
			chunkObject.ChunkMesh.sharedMesh = mesh;
			mesh2.SetVertices(_vertices);
			mesh2.subMeshCount = 2;
			mesh2.SetTriangles(_triangles[0], 0);
			mesh2.SetTriangles(_triangles[3], 1);
			chunkObject.ChunkCollider.enabled = false;
			chunkObject.ChunkCollider.sharedMesh = mesh2;
			chunkObject.ChunkCollider.enabled = true;
		}

		private static bool IsFaceRenderable(BlockVolume currentBlockVolume, bool currentBlockIsCutout, Block current, Block faceNeighbour, FaceDirection faceDirection)
		{
			if (faceNeighbour.Volume() != 0)
			{
				return true;
			}
			if ((currentBlockVolume == BlockVolume.HalfTop && faceDirection == FaceDirection.Bottom) || (currentBlockVolume == BlockVolume.HalfBottom && faceDirection == FaceDirection.Top))
			{
				return true;
			}
			if (!currentBlockIsCutout && faceNeighbour.IsCutout())
			{
				return true;
			}
			if (faceNeighbour.IsCollapsedBlock())
			{
				return true;
			}
			BlockType type = current.Type;
			BlockType type2 = faceNeighbour.Type;
			if (currentBlockIsCutout && type != BlockType.Glass && type2 == BlockType.Glass)
			{
				return true;
			}
			return !faceNeighbour.IsSolid() && (type != BlockType.Water || type2 != BlockType.Water);
		}

		private static bool UseSmoothLight(Block block)
		{
			return _smoothLight && block.Type != BlockType.Light && block.Type != BlockType.Lava && block.Type != BlockType.Glass;
		}

		private static void CalculateUVBorder(Block current, Block front, Block back, Block left, Block right)
		{
			_border[0] = false;
			_border[1] = false;
			_border[2] = false;
			_border[3] = false;
			if (!front.IsSolid() || (current.Type == BlockType.Glass && front.IsSolid() && front.Type != BlockType.Glass))
			{
				_border[0] = true;
			}
			if (!back.IsSolid() || (current.Type == BlockType.Glass && back.IsSolid() && back.Type != BlockType.Glass))
			{
				_border[1] = true;
			}
			if (!left.IsSolid() || (current.Type == BlockType.Glass && left.IsSolid() && left.Type != BlockType.Glass))
			{
				_border[2] = true;
			}
			if (!right.IsSolid() || (current.Type == BlockType.Glass && right.IsSolid() && right.Type != BlockType.Glass))
			{
				_border[3] = true;
			}
		}

		private static byte GetMaxValue(byte[] array)
		{
			byte b = 0;
			for (int i = 0; i < array.Length; i++)
			{
				if (array[i] > b)
				{
					b = array[i];
				}
			}
			return b;
		}

		private static void CreateSpriteBlock(Block top, Block front, Block left, Block back, Block right, Block bottom, Block block, Chunk chunk, int x, int y, int z)
		{
			_lightNeighbours[0] = left.Light;
			_lightNeighbours[1] = right.Light;
			_lightNeighbours[2] = top.Light;
			_lightNeighbours[3] = bottom.Light;
			_lightNeighbours[4] = front.Light;
			_lightNeighbours[5] = back.Light;
			int maxValue = GetMaxValue(_lightNeighbours);
			_border[0] = false;
			_border[1] = false;
			_border[2] = false;
			_border[3] = false;
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			int submesh = SelectSubMesh(block.Type);
			int submesh2 = SelectSubMesh(block.Type, colliderOnly: true);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag1_1, _vectorDiag1_2, _vectorDiag1_3, _vectorDiag1_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag2_1, _vectorDiag2_2, _vectorDiag2_3, _vectorDiag2_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag3_1, _vectorDiag3_2, _vectorDiag3_3, _vectorDiag3_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag4_1, _vectorDiag4_2, _vectorDiag4_3, _vectorDiag4_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag5_1, _vectorDiag5_2, _vectorDiag5_3, _vectorDiag5_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vectorDiag6_1, _vectorDiag6_2, _vectorDiag6_3, _vectorDiag6_4, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector010, _vector011, _vector111, _vector110, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector000, _vector100, _vector101, _vector001, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector100, _vector110, _vector111, _vector101, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector001, _vector011, _vector010, _vector000, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector101, _vector111, _vector011, _vector001, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
			CreateFace(submesh2, block.TextureTopUV(), _border, _pos, _vector000, _vector010, _vector110, _vector100, maxValue, maxValue, maxValue, maxValue, block.Type, BlockVolume.Full);
		}

		private static void CreateTopFace(Block top, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = top.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && top.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x, y + 1, z + 1];
					Block block3 = chunk[x, y + 1, z - 1];
					Block block4 = chunk[x + 1, y + 1, z];
					Block block5 = chunk[x - 1, y + 1, z];
					Block block6 = chunk[x + 1, y + 1, z + 1];
					Block block7 = chunk[x - 1, y + 1, z + 1];
					Block block8 = chunk[x + 1, y + 1, z - 1];
					Block block9 = chunk[x - 1, y + 1, z - 1];
					c4 = top.Light + block3.Light + block9.Light + block5.Light >> 2;
					c3 = top.Light + block2.Light + block7.Light + block5.Light >> 2;
					c2 = top.Light + block2.Light + block6.Light + block4.Light >> 2;
					c = top.Light + block3.Light + block8.Light + block4.Light >> 2;
				}
				if (_voxelBorder && !top.IsSolid())
				{
					Block front = chunk[x, y, z + 1];
					Block back = chunk[x, y, z - 1];
					Block left = chunk[x - 1, y, z];
					Block right = chunk[x + 1, y, z];
					CalculateUVBorder(block, front, back, left, right);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector010, _vector011, _vector111, _vector110, c4, c3, c2, c, block.Type, BlockVolume.Full);
			}
			else if (blockVolume == BlockVolume.HalfBottom)
			{
				CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vector050, _vector051, _vector151, _vector150, c4, c3, c2, c, block.Type, blockVolume);
			}
			else
			{
				CreateFace(submesh, block.TextureTopUV(), _border, _pos, _vector010, _vector011, _vector111, _vector110, c4, c3, c2, c, block.Type, blockVolume);
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureTopUV(), _border, _pos, _vector010, _vector011, _vector111, _vector110, c4, c3, c2, c, block.Type, blockVolume);
			}
		}

		private static void CreateBottomFace(Block bottom, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = bottom.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && bottom.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x, y - 1, z + 1];
					Block block3 = chunk[x, y - 1, z - 1];
					Block block4 = chunk[x + 1, y - 1, z];
					Block block5 = chunk[x - 1, y - 1, z];
					Block block6 = chunk[x + 1, y - 1, z + 1];
					Block block7 = chunk[x - 1, y - 1, z + 1];
					Block block8 = chunk[x + 1, y - 1, z - 1];
					Block block9 = chunk[x - 1, y - 1, z - 1];
					c4 = bottom.Light + block3.Light + block9.Light + block5.Light >> 2;
					c = bottom.Light + block2.Light + block7.Light + block5.Light >> 2;
					c2 = bottom.Light + block2.Light + block6.Light + block4.Light >> 2;
					c3 = bottom.Light + block3.Light + block8.Light + block4.Light >> 2;
				}
				if (_voxelBorder && !bottom.IsSolid())
				{
					Block right = chunk[x, y, z + 1];
					Block left = chunk[x, y, z - 1];
					Block back = chunk[x - 1, y, z];
					Block front = chunk[x + 1, y, z];
					CalculateUVBorder(block, front, back, left, right);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector000, _vector100, _vector101, _vector001, c4, c3, c2, c, block.Type, BlockVolume.Full);
			}
			else if (blockVolume == BlockVolume.HalfTop)
			{
				CreateFace(submesh, block.TextureBottomUV(), _border, _pos, _vector050, _vector150, _vector151, _vector051, c4, c3, c2, c, block.Type, blockVolume);
			}
			else
			{
				CreateFace(submesh, block.TextureBottomUV(), _border, _pos, _vector000, _vector100, _vector101, _vector001, c4, c3, c2, c, block.Type, blockVolume);
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureBottomUV(), _border, _pos, _vector000, _vector100, _vector101, _vector001, c4, c3, c2, c, block.Type, blockVolume);
			}
		}

		private static void CreateLeftFace(Block left, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = left.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && left.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x + 1, y + 1, z];
					Block block3 = chunk[x + 1, y - 1, z];
					Block block4 = chunk[x + 1, y, z + 1];
					Block block5 = chunk[x + 1, y, z - 1];
					Block block6 = chunk[x + 1, y + 1, z + 1];
					Block block7 = chunk[x + 1, y + 1, z - 1];
					Block block8 = chunk[x + 1, y - 1, z + 1];
					Block block9 = chunk[x + 1, y - 1, z - 1];
					c4 = left.Light + block3.Light + block9.Light + block5.Light >> 2;
					c3 = left.Light + block2.Light + block7.Light + block5.Light >> 2;
					c2 = left.Light + block2.Light + block6.Light + block4.Light >> 2;
					c = left.Light + block3.Light + block8.Light + block4.Light >> 2;
				}
				if (_voxelBorder && !left.IsSolid())
				{
					Block front = chunk[x, y + 1, z];
					Block back = chunk[x, y - 1, z];
					Block left2 = chunk[x, y, z - 1];
					Block right = chunk[x, y, z + 1];
					CalculateUVBorder(block, front, back, left2, right);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector100, _vector110, _vector111, _vector101, c4, c3, c2, c, block.Type, BlockVolume.Full);
			}
			else
			{
				switch (blockVolume)
				{
				case BlockVolume.HalfBottom:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector100, _vector150, _vector151, _vector101, c4, c3, c2, c, block.Type, blockVolume);
					break;
				case BlockVolume.HalfTop:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector150, _vector110, _vector111, _vector151, c4, c3, c2, c, block.Type, blockVolume);
					break;
				default:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector100, _vector110, _vector111, _vector101, c4, c3, c2, c, block.Type, blockVolume);
					break;
				}
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureUV(), _border, _pos, _vector100, _vector110, _vector111, _vector101, c4, c3, c2, c, block.Type, blockVolume);
			}
		}

		private static void CreateRightFace(Block right, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = right.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && right.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x - 1, y + 1, z];
					Block block3 = chunk[x - 1, y - 1, z];
					Block block4 = chunk[x - 1, y, z + 1];
					Block block5 = chunk[x - 1, y, z - 1];
					Block block6 = chunk[x - 1, y + 1, z + 1];
					Block block7 = chunk[x - 1, y + 1, z - 1];
					Block block8 = chunk[x - 1, y - 1, z + 1];
					Block block9 = chunk[x - 1, y - 1, z - 1];
					c4 = (right.Light + block3.Light + block8.Light + block4.Light) / 5;
					c3 = (right.Light + block2.Light + block6.Light + block4.Light) / 5;
					c2 = (right.Light + block2.Light + block7.Light + block5.Light) / 5;
					c = (right.Light + block3.Light + block9.Light + block5.Light) / 5;
				}
				if (_voxelBorder && !right.IsSolid())
				{
					Block front = chunk[x, y + 1, z];
					Block back = chunk[x, y - 1, z];
					Block left = chunk[x, y, z + 1];
					Block right2 = chunk[x, y, z - 1];
					CalculateUVBorder(block, front, back, left, right2);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector001, _vector011, _vector010, _vector000, c4, c3, c2, c, block.Type, BlockVolume.Full);
			}
			else
			{
				switch (blockVolume)
				{
				case BlockVolume.HalfBottom:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector001, _vector051, _vector050, _vector000, c4, c3, c2, c, block.Type, blockVolume);
					break;
				case BlockVolume.HalfTop:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector051, _vector011, _vector010, _vector050, c4, c3, c2, c, block.Type, blockVolume);
					break;
				default:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector001, _vector011, _vector010, _vector000, c4, c3, c2, c, block.Type, blockVolume);
					break;
				}
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureUV(), _border, _pos, _vector001, _vector011, _vector010, _vector000, c4, c3, c2, c, block.Type, blockVolume);
			}
		}

		private static void CreateFrontFace(Block front, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = front.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && front.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x, y + 1, z + 1];
					Block block3 = chunk[x, y - 1, z + 1];
					Block block4 = chunk[x + 1, y, z + 1];
					Block block5 = chunk[x - 1, y, z + 1];
					Block block6 = chunk[x + 1, y + 1, z + 1];
					Block block7 = chunk[x - 1, y + 1, z + 1];
					Block block8 = chunk[x + 1, y - 1, z + 1];
					Block block9 = chunk[x - 1, y - 1, z + 1];
					c4 = (front.Light + block3.Light + block9.Light + block5.Light) / 5;
					c3 = (front.Light + block3.Light + block8.Light + block4.Light) / 5;
					c2 = (front.Light + block2.Light + block6.Light + block4.Light) / 5;
					c = (front.Light + block2.Light + block7.Light + block5.Light) / 5;
				}
				if (_voxelBorder && !front.IsSolid())
				{
					Block front2 = chunk[x, y + 1, z];
					Block back = chunk[x, y - 1, z];
					Block right = chunk[x - 1, y, z];
					Block left = chunk[x + 1, y, z];
					CalculateUVBorder(block, front2, back, left, right);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector101, _vector111, _vector011, _vector001, c3, c2, c, c4, block.Type, BlockVolume.Full);
			}
			else
			{
				switch (blockVolume)
				{
				case BlockVolume.HalfBottom:
					CreateFace(submesh, block.TextureSideUV(), _border, _pos, _vector101, _vector151, _vector051, _vector001, c3, c2, c, c4, block.Type, blockVolume);
					break;
				case BlockVolume.HalfTop:
					CreateFace(submesh, block.TextureSideUV(), _border, _pos, _vector151, _vector111, _vector011, _vector051, c3, c2, c, c4, block.Type, blockVolume);
					break;
				default:
					CreateFace(submesh, block.TextureSideUV(), _border, _pos, _vector101, _vector111, _vector011, _vector001, c3, c2, c, c4, block.Type, blockVolume);
					break;
				}
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureSideUV(), _border, _pos, _vector101, _vector111, _vector011, _vector001, c3, c2, c, c4, block.Type, blockVolume);
			}
		}

		private static void CreateBackFace(Block back, Block block, Chunk chunk, int x, int y, int z, bool collisionFace)
		{
			int c3;
			int c2;
			int c;
			int c4 = c3 = (c2 = (c = back.Light));
			int submesh = 2;
			if (!collisionFace)
			{
				if (!_lightAttenuation && back.Light == 51)
				{
					c4 = (c3 = (c2 = (c = 200)));
				}
				if (UseSmoothLight(block))
				{
					Block block2 = chunk[x, y + 1, z - 1];
					Block block3 = chunk[x, y - 1, z - 1];
					Block block4 = chunk[x + 1, y, z - 1];
					Block block5 = chunk[x - 1, y, z - 1];
					Block block6 = chunk[x + 1, y + 1, z - 1];
					Block block7 = chunk[x - 1, y + 1, z - 1];
					Block block8 = chunk[x + 1, y - 1, z - 1];
					Block block9 = chunk[x - 1, y - 1, z - 1];
					c4 = back.Light + block3.Light + block9.Light + block5.Light >> 2;
					c3 = back.Light + block2.Light + block7.Light + block5.Light >> 2;
					c2 = back.Light + block2.Light + block6.Light + block4.Light >> 2;
					c = back.Light + block3.Light + block8.Light + block4.Light >> 2;
				}
				if (_voxelBorder && !back.IsSolid())
				{
					Block front = chunk[x, y + 1, z];
					Block back2 = chunk[x, y - 1, z];
					Block left = chunk[x - 1, y, z];
					Block right = chunk[x + 1, y, z];
					CalculateUVBorder(block, front, back2, left, right);
				}
				submesh = SelectSubMesh(block.Type);
			}
			else
			{
				_border[0] = false;
				_border[1] = false;
				_border[2] = false;
				_border[3] = false;
			}
			_pos.x = x;
			_pos.y = y;
			_pos.z = z;
			BlockVolume blockVolume = block.Volume();
			if (collisionFace)
			{
				CreateFace(submesh, _collisionUV, _border, _pos, _vector000, _vector010, _vector110, _vector100, c4, c3, c2, c, block.Type, BlockVolume.Full);
			}
			else
			{
				switch (blockVolume)
				{
				case BlockVolume.HalfBottom:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector000, _vector050, _vector150, _vector100, c4, c3, c2, c, block.Type, blockVolume);
					break;
				case BlockVolume.HalfTop:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector050, _vector010, _vector110, _vector150, c4, c3, c2, c, block.Type, blockVolume);
					break;
				default:
					CreateFace(submesh, block.TextureUV(), _border, _pos, _vector000, _vector010, _vector110, _vector100, c4, c3, c2, c, block.Type, blockVolume);
					break;
				}
			}
			if (block.IsCutoutCollisionBlock())
			{
				CreateFace(3, block.TextureUV(), _border, _pos, _vector000, _vector010, _vector110, _vector100, c4, c3, c2, c, block.Type, blockVolume);
			}
		}

		private static int SelectSubMesh(BlockType blockType, bool colliderOnly = false)
		{
			if (colliderOnly)
			{
				return 3;
			}
			int result = 0;
			switch (blockType)
			{
			case BlockType.Water:
				result = 1;
				break;
			case BlockType.Foliage:
			case BlockType.LightGreenFoliage:
			case BlockType.BlueFoliage:
			case BlockType.RedFoliage:
			case BlockType.Glass:
			case BlockType.Bush:
				result = 2;
				break;
			}
			return result;
		}

		private static void CreateFace(int submesh, Vector2 texUV, bool[] border, Vector3 pos, Vector3 v1, Vector3 v2, Vector3 v3, Vector3 v4, int c1, int c2, int c3, int c4, BlockType type, BlockVolume volume)
		{
			int count = _vertices.Count;
			_vertices.Add(pos + v1);
			_vertices.Add(pos + v2);
			_vertices.Add(pos + v3);
			_vertices.Add(pos + v4);
			_triangles[submesh].Add(count);
			_triangles[submesh].Add(count + 1);
			_triangles[submesh].Add(count + 2);
			_triangles[submesh].Add(count + 2);
			_triangles[submesh].Add(count + 3);
			_triangles[submesh].Add(count);
			byte b = (byte)c1;
			byte b2 = (byte)c2;
			byte b3 = (byte)c3;
			byte b4 = (byte)c4;
			Color32 item = new Color32(0, 0, 0, 0);
			item.r = (item.g = (item.b = b));
			_colors.Add(item);
			item.r = (item.g = (item.b = b2));
			_colors.Add(item);
			item.r = (item.g = (item.b = b3));
			_colors.Add(item);
			item.r = (item.g = (item.b = b4));
			_colors.Add(item);
			float num = 0.125f;
			float num2 = 0.06f;
			float num3 = 0.001f;
			float y = 0f;
			float num4 = 0f;
			float x = 0f;
			float num5 = 0f;
			if (_voxelBorder)
			{
				if (!_border[1])
				{
					y = num2;
				}
				if (!_border[0])
				{
					num4 = 0f - num2;
				}
				if (!_border[2])
				{
					x = num2;
				}
				if (!_border[3])
				{
					num5 = 0f - num2;
				}
			}
			Vector2 item2 = default(Vector2);
			item2.x = texUV.x + num3;
			item2.y = texUV.y + num3;
			_uvs.Add(item2);
			item2.x = texUV.x + num3;
			item2.y = texUV.y + num - num3;
			_uvs.Add(item2);
			item2.x = texUV.x + num - num3;
			item2.y = texUV.y + num - num3;
			_uvs.Add(item2);
			item2.x = texUV.x + num - num3;
			item2.y = texUV.y + num3;
			_uvs.Add(item2);
			item2.x = x;
			item2.y = y;
			_uvs2.Add(item2);
			item2.x = x;
			item2.y = 1f + num4;
			_uvs2.Add(item2);
			item2.x = 1f + num5;
			item2.y = 1f + num4;
			_uvs2.Add(item2);
			item2.x = 1f + num5;
			item2.y = y;
			_uvs2.Add(item2);
		}

		private static void SetBlockLight(World world, Block block)
		{
			if (block.Type != BlockType.Light)
			{
				return;
			}
			block.Light = byte.MaxValue;
			block.Chunk.SetDirty();
			for (int i = -2; i <= 2; i++)
			{
				for (int j = -2; j <= 2; j++)
				{
					for (int k = -2; k <= 2; k++)
					{
						Block block2 = world[block._wx + i, block._wy + j, block._wz + k];
						if (!block2.IsSolid())
						{
							block2.Light = byte.MaxValue;
							if (block2.Chunk != null)
							{
								block2.Chunk.SetDirty();
							}
						}
					}
				}
			}
		}

		private static void MarkLightBlockIfNeeded(Block block)
		{
			if (block.Type == BlockType.Light)
			{
				_lightBlocks.Add(block);
			}
		}

		public static void UpdateHeightColumn(World world, int x, int z)
		{
			int num = world.WorldVisibleSizeY - 1;
			bool flag = false;
			for (int num2 = num; num2 >= 0; num2--)
			{
				Block block = world[x, num2, z];
				if (block.IsSolid() || block.Type == BlockType.Water)
				{
					if (!flag)
					{
						Block block2 = world[x, num2 + 1, z];
						if (!block2.IsSolid() && block2.Type != BlockType.Water)
						{
							block2.Type = BlockType.Height;
							block2.Light = byte.MaxValue;
							flag = true;
						}
					}
				}
				else
				{
					if (!flag)
					{
						block.Light = byte.MaxValue;
					}
					if (block.Type == BlockType.Height)
					{
						block.Type = BlockType.Air;
					}
				}
			}
		}

		public static void ForceUpdateHeightMap(World world)
		{
			_lightBlocks.Clear();
			int worldVisibleSizeX = world.WorldVisibleSizeX;
			int worldVisibleSizeZ = world.WorldVisibleSizeZ;
			int worldVisibleSizeY = world.WorldVisibleSizeY;
			for (int i = 0; i < worldVisibleSizeX; i++)
			{
				for (int j = 0; j < worldVisibleSizeZ; j++)
				{
					bool flag = false;
					for (int num = worldVisibleSizeY - 1; num >= 0; num--)
					{
						Block block = world[i, num, j];
						block.Light = 0;
						if (block.IsSolid() && !block.IsTranslucent())
						{
							MarkLightBlockIfNeeded(block);
							Block block2 = world[i, num + 1, j];
							if (!block2.IsSolid() && !block2.IsTranslucent())
							{
								if (!flag)
								{
									if (block.Type == BlockType.Water)
									{
										block.Light = byte.MaxValue;
									}
									block2.Type = BlockType.Height;
									block2.Light = byte.MaxValue;
									flag = true;
								}
								if (block.Type == BlockType.Lava)
								{
									block.Light = byte.MaxValue;
									block2.Light = byte.MaxValue;
								}
							}
						}
						else
						{
							if (!flag)
							{
								block.Light = byte.MaxValue;
							}
							if (block.Type == BlockType.Height)
							{
								block.Type = BlockType.Air;
							}
						}
					}
				}
			}
			for (int k = 0; k < _lightBlocks.Count; k++)
			{
				SetBlockLight(world, _lightBlocks[k]);
			}
		}

		public static void ForceLightningFloodArea(World world)
		{
			int num = world.WorldVisibleSizeX - 1;
			int num2 = world.WorldVisibleSizeZ - 1;
			int num3 = world.WorldVisibleSizeY - 1;
			for (int i = 0; i <= num; i++)
			{
				for (int j = 0; j <= num2; j++)
				{
					for (int num4 = num3 - 1; num4 >= 0; num4--)
					{
						Block block = world[i, num4, j];
						if (block != null)
						{
							LightningFlood(world, i, num4, j, block.Light, block);
						}
					}
				}
			}
		}

		public static void UpdateHeightMap(World world, Vector3i worldPos, int lightSpread = 5)
		{
			_lightBlocks.Clear();
			int num = worldPos.x - lightSpread;
			int num2 = worldPos.x + lightSpread;
			int num3 = worldPos.z - lightSpread;
			int num4 = worldPos.z + lightSpread;
			int worldVisibleSizeY = world.WorldVisibleSizeY;
			int num5 = num - 1;
			int num6 = num2 + 1;
			int num7 = num3 - 1;
			int num8 = num4 + 1;
			int num9 = worldVisibleSizeY - 1;
			for (int i = num5; i <= num6; i++)
			{
				for (int j = num7; j <= num8; j++)
				{
					bool flag = false;
					for (int num10 = num9; num10 >= 0; num10--)
					{
						Block block = world[i, num10, j];
						if (i >= num && i <= num2 && j >= num3 && j <= num4 && num10 <= worldVisibleSizeY)
						{
							block.Light = 0;
						}
						if (block.IsSolid() && !block.IsTranslucent())
						{
							MarkLightBlockIfNeeded(block);
							Block block2 = world[i, num10 + 1, j];
							if (!block2.IsSolid() && !block2.IsTranslucent())
							{
								if (!flag)
								{
									if (block.Type == BlockType.Water)
									{
										block.Light = byte.MaxValue;
									}
									block2.Type = BlockType.Height;
									block2.Light = byte.MaxValue;
									flag = true;
								}
								if (block.Type == BlockType.Lava)
								{
									block.Light = byte.MaxValue;
									block2.Light = byte.MaxValue;
								}
							}
						}
						else
						{
							if (!flag)
							{
								block.Light = byte.MaxValue;
							}
							if (block.Type == BlockType.Height)
							{
								block.Type = BlockType.Air;
							}
						}
					}
				}
			}
			for (int k = 0; k < _lightBlocks.Count; k++)
			{
				SetBlockLight(world, _lightBlocks[k]);
			}
		}

		public static void LightningFloodArea(World world, Vector3i worldPos, int lightSpread = 5)
		{
			int num = worldPos.x - lightSpread;
			int num2 = worldPos.x + lightSpread;
			int num3 = worldPos.z - lightSpread;
			int num4 = worldPos.z + lightSpread;
			int num5 = world.WorldVisibleSizeY - 1;
			for (int i = num - 1; i <= num2 + 1; i++)
			{
				for (int j = num3 - 1; j <= num4 + 1; j++)
				{
					for (int num6 = num5; num6 >= 0; num6--)
					{
						Block block = world[i, num6, j];
						if (block != null)
						{
							LightningFlood(world, i, num6, j, block.Light, block);
						}
					}
				}
			}
		}

		private static void LightningFlood(World world, int x, int y, int z, byte light, Block firstStepBlock = null)
		{
			Block block = world[x, y, z];
			block = ((firstStepBlock == null) ? world[x, y, z] : firstStepBlock);
			if (block == null || block.visited || (block.IsSolid() && !block.IsTranslucent() && !block.IsAsteriskTranslucent()) || block.Type == BlockType.Unknown || block.Type == BlockType.WorldBound)
			{
				return;
			}
			byte b = block.Light;
			if (block.IsAsteriskTranslucent())
			{
				b = (byte)((int)b / 2);
			}
			if (firstStepBlock == null)
			{
				light = (byte)(light - 51);
				if (light <= 51 || b >= light)
				{
					return;
				}
				block.visited = true;
				block.Light = light;
				Vector3 vector = default(Vector3);
				vector.x = x;
				vector.y = y;
				vector.z = z;
			}
			LightningFlood(world, x, y + 1, z, light);
			LightningFlood(world, x, y - 1, z, b);
			LightningFlood(world, x, y, z + 1, light);
			LightningFlood(world, x, y, z - 1, light);
			LightningFlood(world, x + 1, y, z, light);
			LightningFlood(world, x - 1, y, z, light);
			block.visited = false;
		}
	}
}
